package com.gem.netty.delay;

import com.gem.entity.Game;
import com.gem.enums.ClientMessageType;
import com.gem.enums.GameRoundStageType;
import com.gem.enums.MessageColorType;
import com.gem.factory.game.GameFactory;
import com.gem.factory.room.RoomFactory;
import com.gem.factory.user.UserFactory;
import com.gem.netty.session.GroupSessionFactory;
import com.gem.utils.R;
import io.netty.channel.Channel;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;

/**
 * 跳过回合
 * Author: Xhy
 * CreateTime: 2022-09-25 21:31
 * 描述：
 *          开启一个线程死循环监听延迟队列中的任务,一旦有找到任务则比较回合计时用户id和当前回合用户id,
 *      如果一致说明该玩家需要跳过被动跳过该回合
 *
 *          到当前回合时 把当前游戏加入到延迟队列，单位为60秒。有任何到下回合的操作把当前任务删除
 */
public class SkipRound {


    private static DelayQueue<DelayTask> delayQueue = new DelayQueue<>();
    private static ConcurrentHashMap<String, DelayTask> mapDelayQueue = new ConcurrentHashMap<>();


    private SkipRound(){

    }

    private static volatile SkipRound skipRound;

    public void remove(Game game){
        DelayTask delayTask = mapDelayQueue.get(game.getRoomId());
        if(delayTask == null)
            return;
        if(delayQueue.remove(delayTask))
            mapDelayQueue.remove(game.getRoomId());
    }

    public void add(Game game,long exprieTime){
        DelayTask task = new DelayTask(game, exprieTime);
        mapDelayQueue.put(game.getRoomId(), task);
        // 此处忽略添加重复 key 的处理
        delayQueue.add(task);
    }

    private static void monitor(){
        Thread thread = new Thread(()->{
            while (true){
                DelayTask task = null;
                try {
                    task = delayQueue.take();
                    Game game = task.getKey();
                    mapDelayQueue.remove(game.getRoomId());
                    String roomId = game.getRoomId();
                    if (game.getCurrentIndex() == game.getCurrentUserNo() % 4){
                        List<Channel> channels = GroupSessionFactory.getGroupSession().getMembersChannel(roomId);
                        String userName = UserFactory.get(game.getUserId());
                        GameFactory.notifyUsers(channels,R.ok().data("color", MessageColorType.SYSTEM_MESSAGE.type).message(userName+" 长时间挂机自动跳过回合")
                                .type(ClientMessageType.PASSIVITY_SKIP_ROUND.type),roomId);
                        GameFactory.roundStage(roomId);
                    }
                    RoomFactory.clear();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        });
        thread.setName("长时间挂机自动跳过回合thread");
        thread.setDaemon(true);
        thread.start();
    }
    /**
     * 回合给下一个用户
     */
    private static void setUserRound(Game game){
        int currentUserIndex = (game.getCurrentIndex()+1) % game.getUsers().size();
        game.setCurrentIndex(currentUserIndex);
        game.setCurrentUserNo(currentUserIndex);
        game.setUserId(game.getUsers().get(currentUserIndex).getId());
        // 修改状态
        game.getUsers().get(currentUserIndex).setState(GameRoundStageType.WAIT.type);
    }

    public static SkipRound getInstance(){
        if (skipRound == null){
            synchronized (SkipRound.class){
                if (skipRound == null){
                    skipRound = new SkipRound();
                    monitor();
                }
            }
        }
        return skipRound;
    }



    private class DelayTask implements Delayed {

        private Game key;
        /**
         * 过期时间(单位秒)
         */
        private long exprieTime;

        private long currentTime;

        public DelayTask(Game key, long exprieTime) {
            this.key = key;
            this.exprieTime = exprieTime;
            this.currentTime = System.currentTimeMillis();
        }

        @Override
        public long getDelay(TimeUnit unit) {
            // 计算剩余的过期时间
            // 大于 0 说明未过期
            return exprieTime - TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - currentTime);
        }

        @Override
        public int compareTo(Delayed o) {
            // 过期时间长的放置在队列尾部
            if (this.getDelay(TimeUnit.MICROSECONDS) > o.getDelay(TimeUnit.MICROSECONDS)) {
                return 1;
            }
            // 过期时间短的放置在队列头
            if (this.getDelay(TimeUnit.MICROSECONDS) < o.getDelay(TimeUnit.MICROSECONDS)) {
                return -1;
            }

            return 0;
        }

        public Game getKey() {
            return key;
        }
    }
}
